package com.zys.zys_mybatis;

import com.zys.zys_mybatis.utils.StringUtil;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;

/**
 * @BelongsProject: ZYSMybatis
 * @BelongsPackage: com.zys.zys_mybatis
 * @Author: ZYS
 * @CreateTime: 2024-05-30  11:14
 * @Description: TODO
 */
public class SqlExecuteHandler2 {
    private final Method method;
    private final Object[] args;
    private final String sql;
    private final Connection connection;
    private PreparedStatement preparedStatement;

    public SqlExecuteHandler2(Method method, Object[] args, String sql, Connection connection) {
        this.method = method;
        this.args = args;
        this.sql = sql;
        this.connection = connection;
    }

    //Sql解析
    public PreparedStatement parseSql() throws Exception {
        //sql无输入参数的情况
        if (!sql.contains("#")) {
            return connection.prepareStatement(sql);
        }
        //sql有输入参数
        //获取方法参数
        Parameter[] parameters = method.getParameters();
        //方法参数为自定义dto对象的情况
        if (parameters.length == 1 && !isJavaClass(parameters[0].getType())) {
            //进行sql解析和拼接
            return ObjectSqlParse(args[0], sql);
        } else {
            //方法参数为普通值
            return argsSqlParse(parameters, sql);
        }
    }

    //sql有输入参数
    private PreparedStatement argsSqlParse(Parameter[] parameters, String sql) throws Exception {
        //若参数中有参数没有使用@Param注解，则抛出异常
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].getAnnotation(Param.class) == null) {
                throw new RuntimeException("参数" + i + "没有使用@Param注解");
            }
        }
        //将参数名替换为?占位符，这里仅针对#{}
        for (Parameter parameter : parameters) {
            //获取参数名
            String paramName = parameter.getAnnotation(Param.class).value();
            //替换参数名
            sql = sql.replace("#{" + paramName + "}", "?");
        }
        //生成预处理对象
        preparedStatement = connection.prepareStatement(sql);
        //给占位符赋值
        for (int i = 0; i < args.length; i++) {
            preparedStatement.setObject(i + 1, args[i]);
        }
        return preparedStatement;
    }

    //sql有输入参数，且参数为自定义dto对象
    private PreparedStatement ObjectSqlParse(Object methodParameter, String sql) throws Exception {
        //获得所有#{}占位符中参数
        List<String> paramNames = new ArrayList<>();
        String sqlCopy = sql;
        do {
            paramNames.add(sqlCopy.substring(sqlCopy.indexOf("#{") + 2, sqlCopy.indexOf("}")));
            sqlCopy = sqlCopy.substring(sqlCopy.indexOf("}") + 1);
        } while (sqlCopy.contains("#{"));

        //将占位符#{}替换为?占位符
        for (String paramName : paramNames) {
            sql = sql.replace("#{" + paramName + "}", "?");
        }

        preparedStatement = connection.prepareStatement(sql);
        //给占位符赋值
        for (int i = 0; i < paramNames.size(); i++) {
            String methodName = "get" + StringUtil.firstToUpperCase(paramNames.get(i));
            //获得参数对象的get方法
            Method objMethod = methodParameter.getClass().getMethod(methodName);
            //给占位符赋值
            preparedStatement.setObject(i + 1, objMethod.invoke(methodParameter));
        }
        return preparedStatement;
    }

    //判断是否是java类
    private boolean isJavaClass(Class<?> clz) {
        return clz != null && clz.getClassLoader() == null;
    }
}
